package com.beeasy.tools.bean;

import lombok.Data;
import ma.glasnost.orika.CustomMapper;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.MappingContext;
import ma.glasnost.orika.metadata.ClassMapBuilder;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class MapperInitHandlerImpl implements MapperFactoryHolder.InitHandler {

    private MapperHolder holder = new MapperHolder();

    @Override
    public void init(Class src, Class dest, MapperFactory factory) {
        ClassMapBuilder builder = factory.classMap(src, dest);
        analyze(src, dest, builder);
        builder.byDefault().register();
    }


    private void analyze(Class src, Class targetClass, ClassMapBuilder builder){
        //如果有设定mapper
        MapperEntity mapperEntity = (MapperEntity) targetClass.getAnnotation(MapperEntity.class);
        if (mapperEntity != null) {
            if(mapperEntity.ignoreFields().length > 0) {
                for (String s : mapperEntity.ignoreFields()) {
                    builder.exclude(s);
                }
            }
        }
        //是否需要对字段进行追加处理
        ClzInfo destInfo = analyzeClass(targetClass);
        if(!destInfo.hasMapperFields()){
            return;
        }
        builder.customize(new CustomMapper() {
            @Override
            public void mapAtoB(Object o, Object o2, MappingContext context) {
                super.mapAtoB(o, o2, context);
                destInfo.getSetters().entrySet().parallelStream().forEach(e -> {
                    MapperField mapperField = e.getValue().getAnnotation(MapperField.class);
                    Object value = invokeMapper(mapperField, o, e.getKey(), e.getValue().getType());
                    try {
                        e.getValue().set(o2, value);
                    } catch (IllegalAccessException illegalAccessException) {
                        illegalAccessException.printStackTrace();
                    }
                });
            }
        });
//        targetClass
    }


    private ClzInfo analyzeClass(Class clz){
        ClzInfo clzInfo = new ClzInfo();
        while(clz != Object.class){
            for (Field field : clz.getDeclaredFields()) {
                MapperField mapperField = field.getAnnotation(MapperField.class);
                if (mapperField == null) {
                    continue;
                }
                field.setAccessible(true);
                clzInfo.getSetters().put(field.getName(), field);
            }
            clz = clz.getSuperclass();
        }
        return clzInfo;
    }


    private Object invokeMapper(MapperField mapperField, Object object, String fieldName, Class fieldTargetClass){
        AbstractMapper mapper = holder.getAbstractMapper(mapperField);//mapperField.mapper().newInstance();
        if (mapper == null) {
           return null;
        }
        //构造参数
        Object params = mapper.convertParams(mapperField.params());

        Object val = mapper.to(object, fieldName,  params);
        return val;
    }


    @Data
    public static class ClzInfo{
        private Map<String, Field> setters = new ConcurrentHashMap<>();

        public boolean hasMapperFields(){
            return setters.size() > 0;
        }
    }



}
